package com.apexsoft.assets.base.handler;

import com.apexsoft.assets.base.exception.BizException;
import com.apexsoft.assets.base.handler.GlobalExceptionHandler;
import com.apexsoft.assets.base.response.JSONResponse;
import io.grpc.Status;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.exceptions.PersistenceException;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

@Slf4j
@RestControllerAdvice
public class BaseExceptionHandler extends GlobalExceptionHandler {

    public BaseExceptionHandler() {
        super();
    }
    private final String bizExceptionHead = "### Cause: BizException(";

    @Override
    @ExceptionHandler(value = Exception.class)
    public JSONResponse allExceptionHandler(HttpServletRequest request, Exception exception) throws Exception {
        if(exception == null){
            return super.allExceptionHandler(request, null);
        }
        Throwable t = exception;
        while(t.getCause() != null){
            t = t.getCause();
        }
        Integer code = JSONResponse.CODE_FAIL;
        String errMsg=t.getMessage();
        if (StringUtils.isNoneBlank(errMsg) && errMsg.contains(bizExceptionHead)) {
            errMsg = errMsg.substring(errMsg.lastIndexOf(bizExceptionHead) + bizExceptionHead.length());
            errMsg = errMsg.substring(0, errMsg.indexOf(")"));
            String codeStr;
            if(errMsg.contains(", causeMsg=")){
                codeStr = errMsg.substring(errMsg.indexOf("code=")+"code=".length(), errMsg.indexOf(", causeMsg=")).trim();
            }else{
                codeStr=errMsg.substring(errMsg.indexOf("code=")+"code=".length()).trim();
            }
            try {
                code = Integer.parseInt(codeStr);
            } catch (Exception e) {
            }
            errMsg = errMsg.substring(errMsg.indexOf("causeMsg=")+"causeMsg=".length());
        }

        if(StringUtils.isNoneBlank(errMsg)){
            for (Status.Code e:Status.Code.values()){
                String str=e.toString()+":";
                if(errMsg.startsWith(str)){
                    errMsg= errMsg.substring(errMsg.indexOf(str)+str.length());
                    break;
                }
            }
        }
        JSONResponse resp = new JSONResponse(code, errMsg);
        log.error(exception.getMessage(), exception);
        return resp;
    }

    @Override
    @ExceptionHandler(value = BizException.class)
    public JSONResponse validExceptionHandler(HttpServletRequest request, BizException exception) throws Exception {
        if(exception == null){
            return super.allExceptionHandler(request, null);
        }
        Integer code = exception.getCode();
        String errMsg = exception.getCauseMsg();
        if(StringUtils.isBlank(errMsg)) {
            Throwable t = exception;
            while (t.getCause() != null) {
                t = t.getCause();
            }
            errMsg=t.getMessage();
            if (StringUtils.isNoneBlank(errMsg) && errMsg.contains(bizExceptionHead)) {
                errMsg = errMsg.substring(errMsg.lastIndexOf(bizExceptionHead) + bizExceptionHead.length());
                errMsg = errMsg.substring(0, errMsg.indexOf(")"));
                String codeStr;
                if(errMsg.contains(", causeMsg=")){
                    codeStr = errMsg.substring(errMsg.indexOf("code=")+"code=".length(), errMsg.indexOf(", causeMsg=")).trim();
                }else{
                    codeStr=errMsg.substring(errMsg.indexOf("code=")+"code=".length()).trim();
                }
                try {
                    code = Integer.parseInt(codeStr);
                } catch (Exception e) {
                }
                errMsg = errMsg.substring(errMsg.indexOf("causeMsg=")+"causeMsg=".length());
            }
        }
        JSONResponse resp = new JSONResponse(code, errMsg);
        log.error(exception.getMessage(), exception);
        return resp;
    }

    @ExceptionHandler(value = {MyBatisSystemException.class, PersistenceException.class})
    public JSONResponse myBatisSystemExceptionHandler(HttpServletRequest request, MyBatisSystemException exception) throws Throwable {
        if(exception == null){
            return super.allExceptionHandler(request, null);
        }
        Throwable t = exception;
        while(t.getCause() != null){
            t = t.getCause();
        }
        if(t instanceof MyBatisSystemException){
            JSONResponse resp = new JSONResponse(JSONResponse.CODE_FAIL, t.getMessage());
            log.error(exception.getMessage(), exception);
            return resp;
        }
        Method allExceptionHandler = null;
        for(Method method: this.getClass().getDeclaredMethods()){
            ExceptionHandler annotation = method.getAnnotation(ExceptionHandler.class);
            if(annotation != null && annotation.value() != null){
                for(Class clazz: annotation.value()){
                    if(clazz.getName().equals(t.getClass().getName())){
                        return (JSONResponse) method.invoke(this, request, t);
                    }else if(clazz.getName().equals(Exception.class.getName())){
                        allExceptionHandler = method;
                    }
                }
            }
        }
        return (JSONResponse) allExceptionHandler.invoke(this, request, t);
    }

}
